/*************************************************************
*
* DS_LIST.H
* 
* Prefix: lst
*
* Linked list container
*************************************************************/
#ifndef _DS_PTR_LIST_H_
#define _DS_PTR_LIST_H_

namespace ds {

struct PTR_LIST_NODE {
   PTR_LIST_NODE() : pPrev(0), pNext(0) {}

   PTR_LIST_NODE *pPrev;
   PTR_LIST_NODE *pNext;
};

template <typename T> struct LIST_NODE_ACCESS_POLICY {
   static T*   Next    (T* pNode)           { return static_cast<T*>(pNode->pNext); }
   static T*   Prev    (T* pNode)           { return static_cast<T*>(pNode->pPrev); }

   static void SetNext (T* pNode, T* pNext) { pNode->pNext = pNext; }
   static void SetPrev (T* pNode, T* pPrev) { pNode->pPrev = pPrev; }
};

//
template <typename T, typename NODE_ACCESS_POLICY = LIST_NODE_ACCESS_POLICY<T> > class PTR_LIST {
public:
   class C_ITERATOR {
   public:
      C_ITERATOR(T *_pNode = 0) : pNode(_pNode) {}

      bool        IsDone     (void) const { return pNode  == 0; }

      bool        operator== (const C_ITERATOR& other) const { return (pNode == other.pNode); }
      bool        operator!= (const C_ITERATOR& other) const { return (!(*this == other));    }

      const T*    operator-> (void) const { return  pNode; }
      const T&    operator*  (void) const { return *pNode; }

      C_ITERATOR& operator++ (void) { pNode = NODE_ACCESS_POLICY::Next(pNode); return (*this); }
      C_ITERATOR& operator-- (void) { pNode = NODE_ACCESS_POLICY::Prev(pNode); return (*this); }

      C_ITERATOR  operator++ (int)  { C_ITERATOR _Tmp = *this; ++*this; return _Tmp; }
      C_ITERATOR  operator-- (int)  { C_ITERATOR _Tmp = *this; --*this; return _Tmp; }

      T *         Get         (void) { return pNode; }
      const T *   Get         (void) const { return pNode; }

   private:
      T *pNode;
   };

   class ITERATOR : public C_ITERATOR {
   public:
      ITERATOR(T *_pNode = 0) : C_ITERATOR(_pNode) {}

      T&        operator*  (void) const { return ((T&)**(C_ITERATOR *)this); }
      T*        operator-> (void) const { return (&**this); }

      T*        Get        (void)       { return const_cast<T *>(C_ITERATOR::operator->()); }

      ITERATOR& operator++ (void) { ++(*(C_ITERATOR *)this); return (*this);       }
      ITERATOR  operator++ (int)  { ITERATOR _Tmp = *this; ++*this; return _Tmp;   }
      ITERATOR& operator-- (void) { --(*(C_ITERATOR *)this); return (*this);       }
      ITERATOR  operator-- (int)  { ITERATOR _Tmp = *this; --*this; return (_Tmp); }
   };

   PTR_LIST() : pHead(0), pTail(0), length(0) {}

   typedef C_ITERATOR CONST_ITERATOR;

   bool       IsEmpty      (void) const { return pHead == 0; }

   ITERATOR   Insert       (T *val, ITERATOR where); // insert AFTER where!!!
   ITERATOR   PushBack     (T * val) { return Insert(val, Back()); }
   ITERATOR   PushFront    (T * val);

   T*         Erase        (ITERATOR where); // remove from list, but not destroy

   void       Clear        (void);

   ITERATOR   Front        (void)       { return ITERATOR(pHead); }
   C_ITERATOR Front        (void) const { return ITERATOR(pHead); }

   ITERATOR   Back         (void)       { return ITERATOR(pTail); }
   C_ITERATOR Back         (void) const { return ITERATOR(pTail); }

   ITERATOR    Begin       (void) { return Front(); }
   CONST_ITERATOR Begin    (void) const { return Front(); }

   int        Length       (void) const { return length; }

   void Swap(PTR_LIST & p)
   {
      dsSwap(pHead, p.pHead);
      dsSwap(pTail, p.pTail);
      dsSwap(length, p.length);
   }

private:
   T     *pHead, *pTail;
   int    length;
};

} // namespace ds

#include "ds_ptr_list.hpp"

#endif // _DS_PTR_LIST_H_

//
// End-of-file DS_PTR_LIST.H
//
